/*
 * =====================================================================================
 * 
 *       Filename:  thread_proxy_imp.h
 * 
 *    Description:  
 * 
 *        Version:  1.0
 *        Created:  04/11/08 13:32:28 CST
 *       Revision:  none
 *       Compiler:  gcc
 * 
 *         Author:   (), 
 *        Company:  
 * 
 * =====================================================================================
 */

#ifndef  THREAD_PROXY_IMPL_INC
#define  THREAD_PROXY_IMPL_INC

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>


template <class T>
class thread_proxy_impl {
protected:
    typedef struct _thread_param {
	T* obj;
	void ( T::*start_routine)( void*);
	void* arg;
	sem_t sem;
    } thread_param;

    static void* thread_proxy_entry(void* arg)
    {
	thread_param* param_ptr = static_cast<thread_param* >(arg);
	thread_param param = *param_ptr;
	sem_post( &param_ptr->sem);
	(param.obj->*param.start_routine)(param.arg);
    }
public:
    int pthread_create(
	    T* obj, 
	    pthread_t* thread, 
	    const pthread_attr_t *attr,
	    void (T::*start_routine)(void *),
	    void* arg)
    {
	int rt;
	thread_param param = { obj, start_routine, arg};

	sem_init( &param.sem, 0, 0);
	rt = ::pthread_create(thread, attr, &thread_proxy_impl::thread_proxy_entry, static_cast<void*>( &param));
	sem_wait( &param.sem);
	sem_destroy( &param.sem);
	return rt;
    }

};

template<class T>
int thread_proxy(
	T *obj,
	pthread_t *thread,
	const pthread_attr_t *attr,
	void (T::*start_routine)(void*),
	void* arg)
{
    return thread_proxy_impl<T>().pthread_create( obj, thread, attr, start_routine, arg);
}

class Thread {
public:
    Thread() :arg(NULL) {}
    Thread(void* arg){this->arg = arg;}
    const pthread_t getID() {return m_thread;}
    void start() {
	thread_proxy(this, &m_thread, NULL, &Thread::run, arg);
    }
    void join() {
	pthread_join(m_thread, NULL);
    }
    bool operator==(const Thread * const thread) const {
	return m_thread == thread->m_thread;
    }
protected:
    virtual void run(void* arg) = 0;

    void sleepMills(int mills) {
	struct timespec delay;
	delay.tv_sec = mills/1000;
	delay.tv_nsec = (mills % 1000) * 1000000L;
	nanosleep((const struct timespec *)&delay, NULL);
    }
private:
    void* arg;
    pthread_t m_thread;
};

#endif   /* ----- #ifndef THREAD_PROXY_IMPL_INC  ----- */

